package com.keenote.file;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * description
 *
 * @author mic.zhou
 * @date 2022/8/16 18:22
 */
public class FileUtils {
    /**
     * 从CSV读取数据
     *
     * @param split       分隔符
     * @param removeTitle 删除标题
     * @return 结果
     */
    public static List<List<String>> readCsv(String path, String split, boolean removeTitle) {
        try (FileReader fr = new FileReader(path)) {
            BufferedReader reader = new BufferedReader(fr);
            List<List<String>> result = reader.lines().map(i -> Arrays.asList(i.split(split))).collect(Collectors.toList());
            if (removeTitle && !result.isEmpty()) {
                result.remove(0);
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 从CSV读取数据
     *
     * @param split       分隔符
     * @param removeTitle 删除标题
     * @return 结果
     */
    public static List<String> readCsvLine(String path, String split, boolean removeTitle) {
        try (FileReader fr = new FileReader(path)) {
            BufferedReader reader = new BufferedReader(fr);
            List<String> result = reader.lines().collect(Collectors.toList());
            if (removeTitle && !result.isEmpty()) {
                result.remove(0);
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 从CSV读取数据
     *
     * @return 结果
     */
    public static List<List<String>> readCsv(String path) {
        return readCsv(path, ",", false);
    }

    public static List<String> readCsvLine(String path) {
        return readCsvLine(path, ",", false);
    }

    /**
     * 从CSV读取数据
     *
     * @return 结果
     */
    public static List<List<String>> readCsv(String path, boolean removeTitle) {
        return readCsv(path, ",", removeTitle);
    }

    /**
     * 从CSV读取数据
     *
     * @return 结果
     */
    public static List<String> readCsvLine(String path, boolean removeTitle) {
        return readCsvLine(path, ",", removeTitle);
    }

    /**
     * 从CSV读取数据
     *
     * @return 结果
     */
    public static List<List<String>> readExcel(String path) {
        return readExcel(path, false);
    }

    public static List<String> readExcelLine(String path) {
        return readExcelLine(path, false);
    }

    /**
     * 从CSV读取数据
     *
     * @return 结果
     */
    public static List<List<String>> readExcel(String path, boolean removeTitle) {
        try (XSSFWorkbook workbook = new XSSFWorkbook(new File(path))) {
            XSSFSheet sheet = workbook.getSheetAt(0);
            Iterator<Row> rowIterator = sheet.rowIterator();
            List<List<String>> result = new ArrayList<>();
            while (rowIterator.hasNext()) {
                Row row = rowIterator.next();
                Iterator<Cell> iterator = row.cellIterator();
                List<String> rowData = new ArrayList<>();
                while (iterator.hasNext()) {
                    Cell cell = iterator.next();
                    int index = cell.getColumnIndex();
                    while (rowData.size() - 1 < index) {
                        rowData.add("");
                    }
                    rowData.set(index, cell.getStringCellValue());
                    result.add(rowData);
                }
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static List<String> readExcelLine(String path, boolean removeTitle) {
        try (XSSFWorkbook workbook = new XSSFWorkbook(new File(path))) {
            XSSFSheet sheet = workbook.getSheetAt(0);
            Iterator<Row> rowIterator = sheet.rowIterator();
            List<String> result = new ArrayList<>();
            if (removeTitle && rowIterator.hasNext()) {
                rowIterator.next();
            }
            while (rowIterator.hasNext()) {
                Row row = rowIterator.next();
                Cell cell = row.getCell(0);
                result.add(cell.getStringCellValue());
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void writeToCsv(List<List<String>> dataList, String name) {
        if (!name.contains(":\\")) {
            name = System.getenv("APPDATA") + "\\" + name;
        }
        if (!name.endsWith(".csv")) {
            name += "_" + System.currentTimeMillis() / 1000 + ".csv";
        }
        System.out.println("文件名：" + name);
        String context = dataList.stream().map(i -> String.join(",", i)).collect(Collectors.joining("\n"));
        try (FileWriter fileWriter = new FileWriter(name)) {
            fileWriter.write(context);
            fileWriter.flush();
        } catch (Exception e) {
            throw new RuntimeException("文件写入失败！");
        }
    }


    public static void writeLinesToCsv(List<String> dataList, String name) {
        if (!name.contains(":\\")) {
            name = System.getenv("APPDATA") + "\\" + name;
        }
        if (!name.endsWith(".csv")) {
            name += "_" + System.currentTimeMillis() / 1000 + ".csv";
        }
        System.out.println("文件名：" + name);
        String context = String.join("\r\n", dataList);
        try (FileWriter fileWriter = new FileWriter(name)) {
            fileWriter.write(context);
            fileWriter.flush();
        } catch (Exception e) {
            throw new RuntimeException("文件写入失败！");
        }
    }

    /**
     * 写入文件
     *
     * @param content 内容
     * @param name    名字
     */
    public static void writeToFile(String content, String name) {
        try (FileOutputStream fos = new FileOutputStream(name, false)) {
            fos.write(content.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            throw new RuntimeException("文件写入失败！");
        }
    }

    /**
     * 从文件中读取成字符串
     *
     * @param name 名字
     */
    public static String readAsString(String name) {
        try (FileInputStream reader = new FileInputStream(name)) {
            int len = 0;
            byte[] bytes = new byte[1024];
            StringBuilder sb = new StringBuilder();
            while ((len = reader.read(bytes)) != -1) {
                sb.append(new String(bytes, 0, len, StandardCharsets.UTF_8));
            }
            return sb.toString();
        } catch (Exception e) {
            throw new RuntimeException("文件写入失败！");
        }
    }

    /**
     * 从文件中读取成字符串
     *
     * @param name 名字
     */
    public static List<String> readAsStringLine(String name) {
        try (FileReader reader = new FileReader(name)) {
            return new BufferedReader(reader).lines().collect(Collectors.toList());
        } catch (Exception e) {
            throw new RuntimeException("文件读取失败！");
        }
    }

    /**
     * 获取两个文件的交集
     *
     * @param fileA 文件A
     * @param fileB 文件B
     * @return 结果
     */
    public static Set<String> getFileRetain(String fileA, String fileB) {
        List<String> aLines = readLinesBySuffix(fileA);
        List<String> bLines = readLinesBySuffix(fileB);
        if (CollectionUtils.isEmpty(aLines) || CollectionUtils.isEmpty(bLines)) {
            return Collections.emptySet();
        }
        HashSet<String> result = new HashSet<>(aLines);
        result.retainAll(bLines);
        return result;
    }

    /**
     * 获取两个文件的并集
     *
     * @param fileA 文件A
     * @param fileB 文件B
     * @return 结果
     */
    public static Set<String> getFileAll(String fileA, String fileB) {
        List<String> aLines = readLinesBySuffix(fileA);
        List<String> bLines = readLinesBySuffix(fileB);
        if (CollectionUtils.isEmpty(aLines) || CollectionUtils.isEmpty(bLines)) {
            return Collections.emptySet();
        }
        HashSet<String> result = new HashSet<>(aLines);
        result.addAll(bLines);
        return result;
    }

    /**
     * 获取两个文件的差集 source-diff
     *
     * @param source 文件source
     * @param diff   文件diff
     * @return 结果
     */
    public static Set<String> getFileDiff(String source, String diff) {
        List<String> aLines = readLinesBySuffix(source);
        List<String> bLines = readLinesBySuffix(diff);
        if (CollectionUtils.isEmpty(aLines) || CollectionUtils.isEmpty(bLines)) {
            return Collections.emptySet();
        }
        HashSet<String> result = new HashSet<>(aLines);
        result.removeAll(bLines);
        return result;
    }


    private static List<String> readLinesBySuffix(String fileA) {
        List<String> aLines;
        if (fileA.endsWith(".csv")) {
            aLines = readCsvLine(fileA);
        } else if (fileA.endsWith(".xlsx")) {
            aLines = readExcelLine(fileA);

        } else {
            aLines = readAsStringLine(fileA);
        }
        return aLines;
    }

}
